package cn.zhangxiaohang;

import cn.zhangxiaohang.Utils.HttpRequestUtil;
import cn.zhangxiaohang.thread.GetArticleThread;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.swing.filechooser.FileSystemView;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;

public class ArticleApplication {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("单线程查询，请输入1");
        System.out.println("多线程查询，请输入2");
        System.out.println("结束程序，请输入exit");
        String next = null;
        while (scanner.hasNext())
        {
            next = scanner.next();
            if("exit".equals(next))
            {
                System.exit(0);
            }
            if(!"1".equals(next) && !"2".equals(next))
            {
                System.out.println("请重新输入");
                System.out.println("单线程查询，请输入1");
                System.out.println("多线程查询，请输入2");
                System.out.println("结束程序，请输入exit");
            }else {
                break;
            }
        }
        if("1".equals(next))
        {
            getArticleSingleThread();
        }else if("2".equals(next)){
            getArticleByManyThread();
        }
    }
    /*
    * 单线程获取文章信息
    * */
    public static void getArticleSingleThread(){
        List<String> failArticleUrl = new ArrayList<>();
        LocalDateTime start = LocalDateTime.now();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet("文章信息");
        XSSFRow row = sheet.createRow(0);
        XSSFCell cell = row.createCell(0);
        cell.setCellValue("标题");
        XSSFCell cell1 = row.createCell(1);
        cell1.setCellValue("发布时间");
        XSSFCell cell2 = row.createCell(2);
        cell2.setCellValue("logo链接");
        XSSFCell cell3 = row.createCell(3);
        cell3.setCellValue("浏览量");
        //开始的页数
        int startPage = (2-1)*10+1;
        //结束的页数
        int endPage = startPage+9;
        for (int i = 1; i <=60; i++) {
            int currentCount = 1;
            String url = "https://www.aquanliang.com/_next/data/TLvkJPJe-UYg2wHEBZ7F8/blog/page/"+i+".json?page="+i;
            String res = null;
            JSONArray articleList = null;
            int REQUEST_FAIL_COUNT = 10;
            //请求重试
            while (REQUEST_FAIL_COUNT >= currentCount)
            {
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                res = HttpRequestUtil.getStringByGetRequest(url);
                if(res == null)
                {
                    System.out.println("请求失败，当次请求次数:"+currentCount+"==请求url:"+url);
                    currentCount++;
                    try {
                        Thread.sleep(300);

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    continue;
                }
                try {
                    Object parse = JSONObject.parse(res);
                    JSONObject pageProps = getJson(parse, "pageProps", JSONObject.class);
                    articleList = getJson(pageProps, "articleList", JSONArray.class);
                }catch (Exception e){
                    //解析json有问题，本次请求取消
                    e.printStackTrace();
                    System.out.println("获取的json数据有问题，json数据为:"+res);
                    System.out.println("当前url:"+url);
                    currentCount++;
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e1) {
                        e.printStackTrace();
                    }
                    continue;
                }
                if(articleList== null || articleList.size()==0)
                {
                    System.out.println("获取的articleList为空");
                    currentCount++;
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    continue;
                }
                break;
            }
            if(currentCount> REQUEST_FAIL_COUNT)
            {
                System.out.println("url:"+url+"请求失败，原因可能是请求超时或者articleList不存在");
                failArticleUrl.add(url);
                continue;
            }
            System.out.println("请求:"+url+"成功");

            for (int j = 0; j < articleList.size(); j++) {
                //将数据写进excel表中
                //写的时候需要上锁
                int cellCount = 0;
                //获取当前sheet行数,然后将数据写进sheet对应的行中
                int currentSheetRows = sheet.getPhysicalNumberOfRows();
                XSSFRow sheetRow = sheet.createRow(currentSheetRows);
                Object data = articleList.get(j);
                String title = getJson(data, "title", String.class);
                sheetRow.createCell(cellCount).setCellValue(title);
                cellCount++;
                Integer pub_at = getJson(data, "pub_at", Integer.class);
                Date date = new Date(pub_at * 1000l);
                String publishTime = simpleDateFormat.format(date);
                sheetRow.createCell(cellCount).setCellValue(publishTime);
                cellCount++;
                String cover_img = getJson(data, "cover_img", String.class);
                sheetRow.createCell(cellCount).setCellValue(cover_img);
                cellCount++;
                Integer pv = getJson(data, "pv", Integer.class);
                Integer init_pv = getJson(data, "init_pv", Integer.class);
                Integer count =pv+init_pv;
                sheetRow.createCell(cellCount).setCellValue(count);
            }
        }
        try {
            File homeDirectory = FileSystemView.getFileSystemView().getHomeDirectory();
            FileOutputStream fileOutputStream = new FileOutputStream(homeDirectory.getAbsolutePath() + "/单线程文章信息.xlsx");

            if(failArticleUrl.size()>0)
            {
                FileOutputStream stream = new FileOutputStream(homeDirectory.getAbsolutePath() + "/单线程获取数据失败的url.txt");
                for (String s : failArticleUrl) {
                    stream.write(s.getBytes(StandardCharsets.UTF_8));
                    stream.write("\n".getBytes(StandardCharsets.UTF_8));
                }
                stream.flush();
            }
            workbook.write(fileOutputStream);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("文件不存在，请在window系统尝试");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("请在window系统尝试");
        }
        LocalDateTime end = LocalDateTime.now();
        Duration duration = Duration.between(start, end);
        long minutes = duration.toMillis();
        System.out.println("程序执行了:"+minutes/1000+"秒");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 多线程获取文章信息
     */
    public static void getArticleByManyThread(){
        ArrayList<String> failArticleUrl = new ArrayList<>();
        LocalDateTime start = LocalDateTime.now();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet("文章信息");
        XSSFRow row = sheet.createRow(0);
        XSSFCell cell = row.createCell(0);
        cell.setCellValue("标题");
        XSSFCell cell1 = row.createCell(1);
        cell1.setCellValue("发布时间");
        XSSFCell cell2 = row.createCell(2);
        cell2.setCellValue("logo链接");
        XSSFCell cell3 = row.createCell(3);
        cell3.setCellValue("浏览量");
        AtomicInteger atomicInteger = new AtomicInteger(0);
        int threadCount = 6;
        CopyOnWriteArrayList<String> failUrl = new CopyOnWriteArrayList<>();
        for (int i = 1; i <= threadCount; i++) {
            new GetArticleThread(i,sheet,atomicInteger,failUrl).start();
        }

        while (atomicInteger.get() < threadCount)
        {
            //线程没执行完，继续等待
            System.out.println("线程没执行完，主线程等待中");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for (String url : failUrl) {
            String res = null;
            JSONArray articleList = null;
            //请求重试
            int currentCount = 1;
            int REQUEST_FAIL_COUNT = 3;
            while (REQUEST_FAIL_COUNT >= currentCount)
            {
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                res = HttpRequestUtil.getStringByGetRequest(url);
                if(res == null)
                {
                    System.out.println("请求失败，当次请求次数:"+currentCount+"==请求url:"+url);
                    currentCount++;
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    continue;
                }
                try {
                    Object parse = JSONObject.parse(res);
                    JSONObject pageProps = getJson(parse, "pageProps", JSONObject.class);
                    articleList = getJson(pageProps, "articleList", JSONArray.class);
                }catch (Exception e){
                    //解析json有问题，本次请求取消
                    e.printStackTrace();
                    System.out.println("获取的json数据有问题，json数据为:"+res);
                    System.out.println("当前url:"+url);
                    currentCount++;
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e1) {
                        e.printStackTrace();
                    }
                    continue;
                }
                if(articleList== null || articleList.size()==0)
                {
                    System.out.println("获取的articleList为空");
                    currentCount++;
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    continue;
                }
                break;
            }
            if(currentCount> REQUEST_FAIL_COUNT)
            {
                System.out.println("url:"+url+"请求失败，请联系维护人员");
                failArticleUrl.add(url);
                continue;
            }
            System.out.println("请求:"+url+"成功");
            for (int j = 0; j < articleList.size(); j++) {
                //将数据写进excel表中
                //写的时候需要上锁
                int cellCount = 0;
                //获取当前sheet行数,然后将数据写进sheet对应的行中
                int currentSheetRows = sheet.getPhysicalNumberOfRows();
                XSSFRow sheetRow = sheet.createRow(currentSheetRows);
                Object data = articleList.get(j);
                String title = getJson(data, "title", String.class);
                sheetRow.createCell(cellCount).setCellValue(title);
                cellCount++;
                Integer pub_at = getJson(data, "pub_at", Integer.class);
                Date date = new Date(pub_at * 1000l);
                String publishTime = simpleDateFormat.format(date);
                sheetRow.createCell(cellCount).setCellValue(publishTime);
                cellCount++;
                String cover_img = getJson(data, "cover_img", String.class);
                sheetRow.createCell(cellCount).setCellValue(cover_img);
                cellCount++;
                Integer pv = getJson(data, "pv", Integer.class);
                Integer init_pv = getJson(data, "init_pv", Integer.class);
                Integer count =pv+init_pv;
                sheetRow.createCell(cellCount).setCellValue(count);
                cellCount++;
                sheetRow.createCell(cellCount).setCellValue(url);
            }
        }
        try {
            File homeDirectory = FileSystemView.getFileSystemView().getHomeDirectory();
            FileOutputStream fileOutputStream = new FileOutputStream(homeDirectory.getAbsolutePath() + "/多线程文章信息.xlsx");
            workbook.write(fileOutputStream);
            if(failArticleUrl.size()>0)
            {
                FileOutputStream stream = new FileOutputStream(homeDirectory.getAbsolutePath() + "/获取数据失败的url.txt");
                for (String s : failArticleUrl) {
                    stream.write(s.getBytes(StandardCharsets.UTF_8));
                    stream.write("\n".getBytes(StandardCharsets.UTF_8));
                }
                stream.flush();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("文件不存在，请在window系统尝试");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("请在window系统尝试");
        }
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime end = LocalDateTime.now();
        System.out.println("程序开始时间:"+dateTimeFormatter.format(start));
        System.out.println("程序结束时间:"+dateTimeFormatter.format(end));
        Duration duration = Duration.between(start, end);
        long minutes = duration.toMillis();
        System.out.println("程序执行了:"+minutes/1000+"秒");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static <T> T getJson(Object object,String key,Class<T> type){
        JSONObject jsonObject = (JSONObject) object;
        return (T)jsonObject.get(key);
    }
}
